package joelwilson.lucene;

import java.io.IOException;

import org.apache.lucene.store.Directory;
import org.apache.lucene.store.IndexInput;
import org.apache.lucene.store.IndexOutput;
import org.apache.lucene.store.Lock;
import org.apache.lucene.store.LockFactory;

public class CountingDirectory extends Directory implements StatsGatherer {

	private static final long serialVersionUID = 1l;
	
	private boolean showCalls;
	
	private final Directory directory;
	
	public CountingDirectory(Directory directory) {
		this.directory = directory;
		setShowCalls(false);
	}
	
	public CountingDirectory(Directory directory, boolean showCalls) {
		this.directory = directory;
		setShowCalls(showCalls);
	}
	
	public void setShowCalls(boolean showCalls) {
		this.showCalls = showCalls;
	}
	
	public boolean isShowCalls() {
		return showCalls;
	}
	
	private long close = 0l;
	
	@Override
	public void close()  throws IOException {
		close++;
		if (showCalls)
		System.out.println("Closing directory");
		directory.close();
	}

	private long createOutput = 0l;
	
	@Override
	public IndexOutput createOutput(String arg0) throws IOException {
		createOutput++;
		if (showCalls)
		System.out.println("Creating output named: " + arg0);
		return directory.createOutput(arg0);
	}

	private long deleteFile = 0l;
	
	@Override
	public synchronized void deleteFile(String name) throws IOException {
		deleteFile++;
		if (showCalls)
		System.out.println("Deleting file named: " + name);
		directory.deleteFile(name);
	}

	private long openInput = 0l;
	
	@Override
	public IndexInput openInput(String name) throws IOException {
		openInput++;
		if (showCalls)
		System.out.println("Opening input named: " + name);
		return directory.openInput(name);
	}

	private long touchFile = 0l;
	
	@Override
	public void touchFile(String arg0) throws IOException {
		touchFile++;
		if (showCalls)
		System.out.println("Touching file named: " + arg0);
		directory.touchFile(arg0);
	}

	private long clearLock = 0l;
	
	@Override
	public void clearLock(String name) throws IOException {
		clearLock++;
		if (showCalls)
		System.out.println("Clear lock named: " + name);
		directory.clearLock(name);
	}

	private long getLockFactory = 0l;
	
	@Override
	public LockFactory getLockFactory() {
		getLockFactory++;
		return directory.getLockFactory();
	}

	private long getLockID = 0l;
	
	@Override
	public String getLockID() {
		getLockID++;
		return directory.getLockID();
	}

	private long makeLock = 0l;
	
	@Override
	public Lock makeLock(String name) {
		makeLock++;
		if (showCalls)
		System.out.println("Making lock named: " + name);
		return directory.makeLock(name);
	}

	private long openInputWithBufferSize = 0l;
	
	@Override
	public IndexInput openInput(String name, int bufferSize) throws IOException {
		openInputWithBufferSize++;
		if (showCalls)
		System.out.println("Opening Input named: " + name + "; with bufferSize: " + bufferSize);
		return directory.openInput(name, bufferSize);
	}

	private long setLockFactory = 0l;
	
	@Override
	public void setLockFactory(LockFactory lockFactory) {
		setLockFactory++;
		directory.setLockFactory(lockFactory);
	}

	private long sync = 0l;
	
	@Override
	public void sync(String name) throws IOException {
		sync++;
		if (showCalls)
		System.out.println("Sync: " + name);
		directory.sync(name);
	}

	@Override
	public boolean fileExists(String name) throws IOException {
		return directory.fileExists(name);
	}

	@Override
	public long fileLength(String name) throws IOException {
		return directory.fileLength(name);
	}

	@Override
	public long fileModified(String name) throws IOException {
		return directory.fileModified(name);
	}

	@Override
	public String[] listAll() {
		try {
			return directory.listAll();
		} catch (IOException ioException) {
			return new String[]{"IOException while reading directory list: " + ioException.getMessage()};
		} 
	}
	
	public Directory getInnerDirectory() {
		return directory;
	}

	public String getStatistics() {
		// variables
		StringBuffer output = new StringBuffer();
		long totalCalls = 0l;
		
		// assemble stats
		output.append("Clear Lock: ");
		output.append(clearLock);
		output.append("\n");
		totalCalls += clearLock;
		
		output.append("Close: ");
		output.append(close);
		output.append("\n");
		totalCalls += close;
		
		output.append("Create Output: ");
		output.append(createOutput);
		output.append("\n");
		totalCalls += createOutput;
		
		output.append("Delete File: ");
		output.append(deleteFile);
		output.append("\n");
		totalCalls += deleteFile;
		
		output.append("Get Lock Factory: ");
		output.append(getLockFactory);
		output.append("\n");
		totalCalls += getLockFactory;
		
		output.append("Get LockID: ");
		output.append(getLockID);
		output.append("\n");
		totalCalls += getLockID;
		
		output.append("Make Lock: ");
		output.append(makeLock);
		output.append("\n");
		totalCalls += makeLock;
		
		output.append("Open Input: ");
		output.append(openInput);
		output.append("\n");
		totalCalls += openInput;
		
		output.append("Open Input with BufferSize: ");
		output.append(openInputWithBufferSize);
		output.append("\n");
		totalCalls += openInputWithBufferSize;
		
		output.append("Set Lock Factory: ");
		output.append(setLockFactory);
		output.append("\n");
		totalCalls += setLockFactory;
		
		output.append("Sync: ");
		output.append(sync);
		output.append("\n");
		totalCalls += sync;
		
		output.append("Touch File: ");
		output.append(touchFile);
		output.append("\n");
		totalCalls += touchFile;
		
		output.append("Total API Calls: ");
		output.append(totalCalls);
		output.append("\n");
		
		return output.toString();
	}	
	
}
